﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;

namespace Skyworth.CRM.Common
{
    public static class XmlHelper
    {
        #region Get Value
        /// <summary>
        /// Get the text value by xpath, it return null value as defaut.
        /// </summary>
        /// <param name="xmlNode">the current context, an xml document object or an xml node object.</param>
        /// <param name="xPath">xpath value, @attribute to get attribute value.</param>
        /// <returns></returns>
        public static string GetTextByXpath(XmlNode xmlNode, string xPath)
        {
            return GetTextByXpath(xmlNode, xPath, null);
        }


        /// <summary>
        /// Get the text value by xpath.
        /// </summary>
        /// <param name="context">the current context, an xml document object or an xml node object.</param>
        /// <param name="xPath">xpath value, @attribute to get attribute value.</param>
        /// <param name="defaultVal"></param>
        /// <returns></returns>
        public static string GetTextByXpath(XmlNode xmlNode, string xPath, string defaultVal)
        {
            string rtn = string.Empty;
            if (xmlNode != null && xmlNode.SelectSingleNode(xPath) != null)
            {
                rtn = xmlNode.SelectSingleNode(xPath).InnerText;
            }
            if (rtn.Length < 1)
            {
                rtn = defaultVal;
            }
            return rtn;
        }


        public static XmlNode GetXmlNodeByXpath(XmlNode xmlNode, string xpath)
        {
            return xmlNode == null ? null : xmlNode.SelectSingleNode(xpath);
        }

        public static XmlNodeList GetXmlNodeList(XmlNode xmlNode, string xPath)
        {
            return xmlNode == null ? null : xmlNode.SelectNodes(xPath);
        }


        /// <summary>
        /// Get the xml content by xpath, it return null value as defaut.
        /// </summary>
        /// <param name="xmlNode"></param>
        /// <param name="xpath"></param>
        /// <returns></returns>
        public static string GetXmlByXpath(XmlNode xmlNode, string xpath)
        {
            return GetXmlByXpath(xmlNode, xpath, null);
        }


        /// <summary>
        /// Get the xml content by xpath.
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="xpath"></param>
        /// <param name="defaultVal"></param>
        /// <returns></returns>
        public static string GetXmlByXpath(XmlNode xmlNode, string xpath, string defaultVal)
        {
            string rtn = string.Empty;
            if (xmlNode != null && xmlNode.SelectSingleNode(xpath) != null)
            {
                rtn = xmlNode.SelectSingleNode(xpath).InnerXml;
            }
            if (rtn.Length < 1)
            {
                rtn = defaultVal;
            }
            return rtn;
        }

        /// <summary>
        /// Get the string value format by "format" parameter.
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="xpath"></param>
        /// <param name="defaultVal"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static string GetNumberByXpath(XmlDocument xmlDoc, string xpath, string defaultVal, string format)
        {
            string val = GetTextByXpath(xmlDoc, xpath, defaultVal);
            decimal dval;
            if (decimal.TryParse(val, out dval))
            {
                return dval.ToString(format);
            }
            else
            {
                return defaultVal;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="xn"></param>
        /// <param name="xPath"></param>
        /// <param name="defaultVal"></param>
        /// <returns></returns>
        public static string GetTextInXPathNavigator(XPathNavigator xn, string xPath, string defaultVal)
        {
            string rtn = string.Empty;
            if (xn != null && xn.SelectSingleNode(xPath) != null)
            {
                rtn = xn.SelectSingleNode(xPath).Value;
            }
            if (rtn.Length < 1)
            {
                rtn = defaultVal;
            }
            return rtn;
        }

        #endregion


        #region import data
        /// <summary>
        /// Merge imported xml document into the source xml document.
        /// </summary>
        /// <param name="sourceXmlDoc">The source xml document that will be merged.</param>
        /// <param name="xPath">The parameter specify where the xml document will be imported.</param>
        /// <param name="importedXmlDoc">The imported xml node that needs to be imported.</param>
        public static void ImportDocument(XmlDocument sourceXmlDoc, string xPath, XmlNode importedXmlNode)
        {
            XmlNode node = sourceXmlDoc.SelectSingleNode(xPath);
            if (node != null)
            {
                XmlNode enode = sourceXmlDoc.ImportNode(importedXmlNode, true);
                node.AppendChild(enode);
            }
        }




        /// <summary>
        /// Import an xml node into the source xml document. Note: xpath may be pointed to an xml node list.
        /// </summary>
        /// <param name="sourceXmlDoc">The source xml document that will be added a node.</param>
        /// <param name="xPath">The parameter specify where the xml node will be imported.</param>
        /// <param name="name">The name of the node that will be added.</param>
        /// <param name="value">The value of the node that will be added.</param>
        public static void ImportCustomNode(XmlDocument sourceXmlDoc, string xPath, string name, string value)
        {
            XmlNodeList xnl = sourceXmlDoc.SelectNodes(xPath);
            if (xnl != null)
            {
                XmlNode xe;
                foreach (XmlNode xmlNode in xnl)
                {
                    xe = sourceXmlDoc.CreateElement(name);
                    xe.InnerText = value;
                    xmlNode.AppendChild(xe);
                }
            }
        }

        /// <summary>
        /// Import an xml node into an existed xml node.
        /// </summary>
        /// <param name="xmlDoc">The xml document where the existed xml node locates.</param>
        /// <param name="sourceXmlNode">The xml node that will be imported a node.</param>
        /// <param name="name">The name of the node that will be added.</param>
        /// <param name="value">The value of the node that will be added.</param>
        public static void ImportCustomNodeInContext(XmlDocument xmlDoc, XmlNode sourceXmlNode, string name, string value)
        {
            XmlNode xe = xmlDoc.CreateElement(name);
            xe.InnerText = value;
            sourceXmlNode.AppendChild(xe);
        }
        #endregion

        #region Load xml
        /// <summary>
        /// Load an xml 
        /// </summary>
        /// <param name="path"></param>
        /// <param name="isVirtualPath"></param>
        /// <returns></returns>
        public static XmlDocument Load(string path, bool isVirtualPath)
        {
            XmlDocument xmlDoc = new XmlDocument();
            path = isVirtualPath ? HttpContext.Current.Server.MapPath(path) : path;
            xmlDoc.Load(path);
            return xmlDoc;
        }
        #endregion

        #region xslt
        /// <summary>
        /// Transform an xml document to string by an xml transform document specifed by xslPath
        /// </summary>
        /// <param name="sourceXmlDocument">The data of xml document.</param>
        /// <param name="xalist">the xlst document parameter list.</param>
        /// <param name="xslPath"></param>
        /// <param name="isVirtualPath">the parameter to specify whether the path is virtual path.</param>
        /// <param name="cacheable">the swith of open cache. Only when isVirtualPath is true, it will work.</param>
        /// <returns></returns>
        public static string Transform(XmlDocument sourceXmlDocument, XsltArgumentList xalist, string xslPath, bool isVirtualPath, bool cacheable)
        {
            XslCompiledTransform xslt = new XslCompiledTransform();
            xslPath = isVirtualPath ? HttpContext.Current.Server.MapPath(xslPath) : xslPath;
            if (isVirtualPath && cacheable)
            {
                xslt = CacheHelper.GetObjectFromCache<XslCompiledTransform>(xslPath);
                if (xslt == null)
                {
                    xslt.Load(xslPath);
                    if (xslt != null)
                    {
                        CacheHelper.InsertCache(xslPath, xslt, new System.Web.Caching.CacheDependency(xslPath));
                    }
                }
            }
            else
            {
                xslt.Load(xslPath);
            }

            TextWriter twr = new StringWriter();
            try
            {
                xslt.Transform(sourceXmlDocument, xalist, twr);
            }
            catch (Exception) { }
            return twr.ToString();
        }
        #endregion

    }
}
